﻿using KinonekoSoftware.CodariaDB.Utils;

// ReSharper disable ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator
// ReSharper disable ForCanBeConvertedToForeach
// ReSharper disable ReturnTypeCanBeEnumerable.Global
// ReSharper disable UseNullPropagation

namespace KinonekoSoftware.Studio.Utils
{
    public class ArrayRebuild
    {
        public static List<T> Rebuild<T>(ICollection<T> pendingCollection) where T : IHierarchicalObject
        {
            var map               = new Dictionary<string, T>();
            var rebuildCollection = new List<T>(32);

            pendingCollection.ForEach(x => map.TryAdd(x.GetID(), x));

            foreach (var pending in pendingCollection)
            {
                if (pending.IsRoot())
                {
                    rebuildCollection.Add(pending);
                }

                if (pending.HasParent())
                {
                    if (map.TryGetValue(pending.GetParentID(), out var parent))
                    {
                        parent.AppendChild(pending);
                    }
                }
            }

            return rebuildCollection;
        }


        public static List<T> Rebuild<T>(ICollection<T> pendingCollection, out Dictionary<string, T> dict) where T : IHierarchicalObject
        {
            var rebuildCollection = new List<T>(32);
            var map               = new Dictionary<string, T>();

            pendingCollection.ForEach(x => map.TryAdd(x.GetID(), x));

            foreach (var pending in pendingCollection)
            {
                if (pending.IsRoot())
                {
                    rebuildCollection.Add(pending);
                }

                if (pending.HasParent())
                {
                    if (map.TryGetValue(pending.GetParentID(), out var parent))
                    {
                        parent.AppendChild(pending);
                    }
                }
            }

            dict = map;
            return rebuildCollection;
        }


        public static List<SystemCatalog> OrderedRebuild(ICollection<SystemCatalog> pendingCollection, out Dictionary<string, SystemCatalog> dict)
        {
            var rebuildCollection = new List<SystemCatalog>(32);
            var map               = new Dictionary<string, SystemCatalog>();

            pendingCollection.ForEach(x => map.TryAdd(x.GetID(), x));

            foreach (var pending in pendingCollection)
            {
                if (pending.IsRoot())
                {
                    rebuildCollection.Add(pending);
                }

                if (pending.HasParent())
                {
                    if (map.TryGetValue(pending.GetParentID(), out var parent))
                    {
                        parent.AppendChild(pending);
                    }
                }
            }


            MaintainOrder(rebuildCollection);

            dict = map;
            return rebuildCollection;
        }


        public static List<TreeCatalog> RebuildCatalogs(ICollection<TreeCatalog> pendingCollection, out Dictionary<string, TreeCatalog> dict)
        {
            var rebuildCollection = new List<TreeCatalog>(32);
            var map               = new Dictionary<string, TreeCatalog>();

            pendingCollection.ForEach(x => map.TryAdd(x.Id, x));

            foreach (var pending in pendingCollection)
            {
                if (pending.IsRoot())
                {
                    rebuildCollection.Add(pending);
                }

                if (pending.HasParent())
                {
                    if (map.TryGetValue(pending.ParentID, out var parent))
                    {
                        parent.AppendChild(pending);
                    }
                }
            }

            MaintainOrder(rebuildCollection);

            dict = map;
            return rebuildCollection;
        }



        private static void MaintainOrder(List<SystemCatalog> collection)
        {
            collection.Sort((a, b) => (a?.Index ?? -1) - (b?.Index ?? 0));

            for (var i = 0; i < collection.Count; i++)
            {
                MaintainOrderImpl(collection[i]);
            }
        }

        private static void MaintainOrderImpl(SystemCatalog current)
        {
            if (current is null)
            {
                return;
            }

            if (current.HasChildren())
            {
                current.Children.Sort();

                for (var i = 0; i < current.Children.Count; i++)
                {
                    MaintainOrderImpl(current.Children[i]);
                }
            }
        }

        private static void MaintainOrder(List<TreeCatalog> collection)
        {
            collection.Sort((a, b) => (a?.Index ?? -1) - (b?.Index ?? 0));

            for (var i = 0; i < collection.Count; i++)
            {
                MaintainOrderImpl(collection[i]);
            }
        }

        private static void MaintainOrderImpl(TreeCatalog current)
        {
            if (current is null)
            {
                return;
            }

            if (current.Children is not null && current.Children.Count > 0)
            {
                current.Children.Sort((a, b) => (a?.Index ?? -1) - (b?.Index ?? 0));

                for (var i = 0; i < current.Children.Count; i++)
                {
                    MaintainOrderImpl(current.Children[i]);
                }
            }
        }



        public static List<KeywordCatalog> RebuildCatalogs(ICollection<KeywordCatalog> pendingCollection, out Dictionary<string, KeywordCatalog> dict)
        {
            var rebuildCollection = new List<KeywordCatalog>(32);
            var map               = new Dictionary<string, KeywordCatalog>();

            pendingCollection.ForEach(x => map.TryAdd(x.Id, x));

            foreach (var pending in pendingCollection)
            {
                if (pending.IsRoot())
                {
                    rebuildCollection.Add(pending);
                }

                if (pending.HasParent())
                {
                    if (map.TryGetValue(pending.ParentID, out var parent))
                    {
                        parent.AppendChild(pending);
                    }
                    else
                    {
                        rebuildCollection.Add(pending);
                    }
                }
            }

            MaintainOrder(rebuildCollection);

            dict = map;
            return rebuildCollection;
        }

        private static void MaintainOrder(List<KeywordCatalog> collection)
        {
            collection.Sort((a, b) => (a?.Index ?? -1) - (b?.Index ?? 0));

            for (var i = 0; i < collection.Count; i++)
            {
                MaintainOrderImpl(collection[i]);
            }
        }

        private static void MaintainOrderImpl(KeywordCatalog current)
        {
            if (current is null)
            {
                return;
            }

            if (current.Children is not null && current.Children.Count > 0)
            {
                current.Children.Sort((a, b) => (a?.Index ?? -1) - (b?.Index ?? 0));

                for (var i = 0; i < current.Children.Count; i++)
                {
                    MaintainOrderImpl(current.Children[i]);
                }
            }
        }
    }
}